package com.example.wnn.activiti;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;
import lombok.extern.slf4j.Slf4j;
import org.activiti.bpmn.converter.BpmnXMLConverter;
import org.activiti.bpmn.BpmnAutoLayout;
import org.activiti.bpmn.model.*;
import org.activiti.bpmn.model.Process;
import org.activiti.engine.*;
import org.activiti.engine.history.HistoricTaskInstance;
import org.activiti.engine.identity.Group;
import org.activiti.engine.identity.GroupQuery;
import org.activiti.engine.identity.User;
import org.activiti.engine.identity.UserQuery;
import org.activiti.engine.impl.identity.Authentication;
import org.activiti.engine.repository.Deployment;
import org.activiti.engine.repository.DeploymentBuilder;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.runtime.ProcessInstanceQuery;
import org.activiti.engine.task.Comment;
import org.activiti.engine.task.Task;
import org.activiti.engine.task.TaskQuery;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;

import java.util.*;

@Slf4j
@Service
public class WorkflowServiceImpl implements WorkflowService{


    @Autowired
    private RepositoryService repositoryService;

    @Autowired
    private RuntimeService runtimeService;

    @Autowired
    private TaskService taskService;

    @Autowired
    private HistoryService historyService;

    @Autowired
    private IdentityService identityService;


    @Override
    public boolean generateDeployBpmn(String uid, List<String> candidateGroups) {
         uid = String.format(WorkflowUtils.TASKID,"Process",getUUID());

        //创建bpmn模型
        BpmnModel model = new BpmnModel();
        Process process = new Process();
        model.addProcess(process);
        process.setId(uid);
        process.setName(uid);
        List<SequenceFlow>  sequenceFlowList = new ArrayList<>();
        //创建bpmn元素

        StartEvent startEvent = WorkflowUtils.createStartEvent();
        process.addFlowElement(startEvent);
        String previousTaskId="";
        for (int i = 0; i < candidateGroups.size(); i++) {
            int index = i+1;
            String taskId =String.format(WorkflowUtils.TASKID,index,this.getUUID());
            String  candidateGroup = candidateGroups.get(i);
            String taskName  = this.generateTaskName(candidateGroup);
            process.addFlowElement(WorkflowUtils.createUserTask(taskId, taskName, candidateGroup));
            //第一个任务
            if (0 == i){
                sequenceFlowList.add(WorkflowUtils.createSequenceFlow(startEvent.getId(), taskId));
            }
            //中间的任务
            if (i>0){
                sequenceFlowList.add(WorkflowUtils.createSequenceFlow(previousTaskId, taskId));
            }
            previousTaskId = taskId;
        }
        EndEvent endEvent = WorkflowUtils.createEndEvent();
        process.addFlowElement(endEvent);

        sequenceFlowList.add(WorkflowUtils.createSequenceFlow(previousTaskId, endEvent.getId()));
        sequenceFlowList.forEach(sequenceFlow -> {process.addFlowElement(sequenceFlow);});
        // 2.生成BPMN自动布局
        new BpmnAutoLayout(model).execute();

        BpmnXMLConverter bpmnXMLConverter=new BpmnXMLConverter();
        byte[] convertToXML = bpmnXMLConverter.convertToXML(model);
        String bytes=new String(convertToXML);
        bytes = bytes.replaceAll("&lt;","<").replaceAll("&gt;",">");
        log.info(bytes);

        DeploymentBuilder deployment = repositoryService.createDeployment();
        Deployment deploy = deployment.name(uid)
                .addString(uid+".bpmn",bytes)
                .deploy();
        log.info("部署ID："+deploy.getId());
        log.info("部署名称："+deploy.getName());
        return true;
    }

    @Override
    public boolean delFlowDeploy(String uid) {
        uid = String.format(WorkflowUtils.TASKID,"Process",getUUID());
        try {
            //都二个参数不能填true,否则会做级联删除
            repositoryService.deleteDeployment(uid,false);
        }catch (Exception e){
            log.error("删除工作流流程失败:{}",e.getMessage());
            return false;
        }
       return true;

    }

    @Override
    public boolean startWorkFlow(String uid, String businessKey) {
        Assert.isNull(businessKey,"业务绑定ID不能为空");
        Assert.isNull(uid,"审核流程ID不能为空");

        String key  = String.format(WorkflowUtils.TASKID,"Process",getUUID());
        ProcessInstance processInstance = runtimeService.startProcessInstanceByKey(key,businessKey);

        log.info("流程定义id：" + processInstance.getProcessDefinitionId());
        log.info("流程实例id：" + processInstance.getId());
        log.info("当前活动id：" + processInstance.getActivityId());
        log.info("业务id:"+processInstance.getBusinessKey());

        return true;
    }


    @Override
    public List<TaskProgress> selectTaskProgressList(String userId) {
        List<TaskProgress> result = new ArrayList<>();
        TaskQuery taskQuery = taskService.createTaskQuery();
        List<Task> taskList = taskQuery
                .taskCandidateUser(userId)
                .list();

        if (!CollectionUtil.isEmpty(taskList)){
            for (Task task : taskList) {
                TaskProgress taskProgress = new TaskProgress();
                taskProgress.setTaskId(task.getId());
                taskProgress.setTaskName(task.getName());
                taskProgress.setTaskCreateTime(task.getCreateTime());
                taskProgress.setProcessInstanceId(task.getProcessInstanceId());
                result.add(taskProgress);
            }
        }
        this.setBusinessParameter(result);

        return result;
    }

    @Override
    public List<TaskProgress> selectTaskProgressHistroyList(String userId) {
        List<TaskProgress> result = new ArrayList<>();
        List<HistoricTaskInstance> list = historyService.createHistoricTaskInstanceQuery()
                .taskAssignee(userId)
                .list();
        for (HistoricTaskInstance histroTask : list) {
            TaskProgress taskProgress = new TaskProgress();
            taskProgress.setTaskId(histroTask.getId());
            taskProgress.setTaskName(histroTask.getName());
            taskProgress.setProcessInstanceId(histroTask.getProcessInstanceId());
        }
        this.setBusinessParameter(result);
        return result;
    }

    @Override
    public boolean pass(String taskId, String userId, String message) {
        //redis 做个分布式锁，锁住这这个taskId todo
        if (StrUtil.isBlank(message)){
            message ="通过";
        }
        //用户个人拾取任务，其他用户就看不到了
        taskService.claim(taskId,userId);
        try {
            Thread.sleep(500);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        TaskProgress taskProgress = this.selectTaskProgressByTaskId(taskId);
        //用户的审批意见入库
        taskService.addComment(taskId,taskProgress.getProcessInstanceId(),message);

        //当前用户提交任务
        taskService.complete(taskId);

        return true;
    }

    private TaskProgress selectTaskProgressByTaskId(String taskId) {
          TaskQuery taskQuery =  taskService.createTaskQuery();
          Task task =  taskQuery.taskId(taskId).singleResult();

          if (Objects.nonNull(task)){
              TaskProgress taskProgress = new TaskProgress();
              taskProgress.setTaskId(task.getId());
              taskProgress.setProcessInstanceId(task.getProcessInstanceId());
              taskProgress.setTaskName(task.getName());
              taskProgress.setTaskCreateTime(task.getCreateTime());

              ProcessInstanceQuery processInstanceQuery =  runtimeService.createProcessInstanceQuery();
              processInstanceQuery.processInstanceId(task.getProcessInstanceId());
              ProcessInstance processInstance = processInstanceQuery.singleResult();
              if (Objects.nonNull(processInstance)){
                  taskProgress.setBusinessKey(processInstance.getBusinessKey());
              }
              List<Comment> comments =  taskService.getTaskComments(taskId);
              Optional<Comment> first = comments.stream().findFirst();
              if (first.isPresent()){
                 taskProgress.setComment(first.get().getFullMessage());
              }

              ProcessInstance pi=runtimeService// 获取运行时Service
                      .createProcessInstanceQuery() // 创建流程实例查询
                      .processInstanceId(task.getProcessInstanceId()) // 用流程实例ID查询
                      .singleResult();
              if (Objects.nonNull(pi)){
                  taskProgress.setFinish(false);
              }else {
                  taskProgress.setFinish(true);
              }

              return taskProgress;
          }
        return new TaskProgress();
    }



    private void setBusinessParameter(List<TaskProgress> result) {

        Set<String> processInstanceIdList = new HashSet<>();
        for (TaskProgress task : result) {
            if (StrUtil.isNotBlank(task.getBusinessKey())){
                processInstanceIdList.add(task.getProcessInstanceId());
            }
        }
        if (!CollectionUtil.isEmpty(processInstanceIdList)){
            ProcessInstanceQuery processInstanceQuery =  runtimeService.createProcessInstanceQuery();
            processInstanceQuery.processInstanceIds(processInstanceIdList);
            List<ProcessInstance> processInstanceList =  processInstanceQuery.list();

            List<ProcessInstance> runInStanceList=runtimeService// 获取运行时Service
                    .createProcessInstanceQuery() // 创建流程实例查询
                    .processInstanceIds(processInstanceIdList) // 用流程实例ID查询
                    .list();


            if (!CollectionUtil.isEmpty(processInstanceList)){
                for (ProcessInstance processInstance : processInstanceList) {
                    String processInstanceId  =processInstance.getProcessInstanceId();
                    result.forEach(item->{
                        if (processInstanceId.equals(item.getProcessInstanceId())){
                            item.setBusinessKey(processInstance.getBusinessKey());
                        }

                        if (!CollectionUtil.isEmpty(runInStanceList)){
                            Optional<ProcessInstance> first = runInStanceList.stream()
                                    .filter(v -> v.getProcessInstanceId().equals(processInstanceId))
                                    .findFirst();

                            if (first.isPresent()){
                                item.setFinish(false);
                            }else {
                                item.setFinish(true);
                            }
                        }

                         String taskId =  item.getTaskId();
                         if (StrUtil.isNotBlank(taskId)){
                           List<Comment> comments =  taskService.getTaskComments(taskId);
                             Optional<Comment> first = comments.stream().findFirst();
                             if (first.isPresent()){
                                item.setComment(first.get().getFullMessage());
                             }
                         }
                    });
                }
            }
        }
    }

    private static String getUUID() {
        return UUID.randomUUID().toString().replace("-","");
    }

    private static String generateTaskName(String s) {
        String result = "审核";
        if (StrUtil.isBlank(s)){
            return result;
        }
             /*
               目前化工达平台要有的角色及code 对应
             合同管理员:contractManage
                财务管理员:financeManage
                总工程师傅:chiefEngineer
                班组人员:teamsGroups
                采购员:purchaser
                仓储管理员:warehouse
                董事长:chairman
                总经理:generalManage
               */

        switch (s) {
            case "contractManage":
                result = "合同管理员"+result;
                break;
            case "financeManage":
                result = "财务管理员"+result;
                break;
            case "chiefEngineer":
                result = "总工程师"+result;
                break;
            case "teamsGroups":
                result = "班组人员"+result;
                break;
            case "purchaser":
                result = "采购员"+result;
                break;
            case "warehouse":
                result = "仓储管理员"+result;
                break;
            case "chairman":
                result = "董事长"+result;
                break;
            case "generalManage":
                result = "总经理"+result;
                break;
        }
        return result;
    }


    @Override
    public boolean reject(String taksId, String userId, String notes) {
        return false;  // todo
    }

    @Override
    public boolean refreshUser(String userId, String name, List<String> groups) {
        UserQuery userQuery = identityService.createUserQuery();
        User dbUser = userQuery.userId(userId)
                .singleResult();

        List<Group> dbGroups = this.saveGroups(groups);
        User user = null;
        if (Objects.isNull(dbUser)){
            //新增
            user = identityService.newUser(userId);
            user.setFirstName(name);
            user.setPassword("111111");
            identityService.saveUser(user);

        }else {
            //更新
          identityService.deleteUser(userId);
          user = identityService.newUser(userId);
          user.setFirstName(name);
          user.setPassword("111111");
          identityService.saveUser(user);

        }
        Assert.isNull(user,"工作流刷新用户信息失败");
        //保存用户的分组信息

        this.saveRole(userId,dbGroups);

        return true;
    }

    private void saveRole(String userId, List<Group> dbGroups) {
        for (Group dbGroup : dbGroups) {
            identityService.deleteMembership(userId,dbGroup.getId());
            identityService.createMembership(userId, dbGroup.getId());
        }
    }

    private List<Group> saveGroups(List<String> groups) {
        List<Group> result = new ArrayList<>();
       GroupQuery groupQuery = identityService.createGroupQuery();
        for (String group : groups) {
         Group dbGroup =   groupQuery.groupId(group).singleResult();
         if (Objects.isNull(dbGroup)){
             Group g = identityService.newGroup(group);
             //去系统表中查询下 todo
             String name = "";
             g.setName(name);
             identityService.saveGroup(g);
          }else {
             result.add(dbGroup);
         }

        }
       return result;
    }


}
